package mylogger

import (
	"fmt"
	"os"
	"path"
	"time"
)

//往文件里面写日志相关代码

type FileLogger struct {
	Level       LogLevel
	filePath    string //日志文件保存的路径
	fileName    string //日志文件保存的文件名
	fileObj     *os.File
	errFileObj  *os.File
	maxFileSize int64 //日志文件大小，进行切割
}

func NewFileLogger(levelStr, fp, fn string, maxSize int64) *FileLogger {
	LogLevel, err := parseLogLevel(levelStr)
	if err != nil {
		panic(err)
	}
	f1 := &FileLogger{
		Level:       LogLevel,
		filePath:    fp,
		fileName:    fn,
		maxFileSize: maxSize,
	}

	err1 := f1.initFile() //按照文件路径和文件名将文件打开
	if err1 != nil {
		panic(err1)
	}
	return f1
}

//根据指定的日志文件路径和文件名打开日志文件
func (f *FileLogger) initFile() error {
	fullFileName := path.Join(f.filePath, f.fileName)
	fileObj, err := os.OpenFile(fullFileName, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
	if err != nil {
		fmt.Printf("open log file failed,err:%v\n", err)
		return err
	}

	errFileObj, err1 := os.OpenFile(fullFileName+".err", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
	if err1 != nil {
		fmt.Printf("open err log file failed,err1:%v\n", err1)
		return err1
	}

	//日志文件都已经打开
	f.fileObj = fileObj
	f.errFileObj = errFileObj
	return nil
}

func (f *FileLogger) Close() {
	f.fileObj.Close()
	f.errFileObj.Close()
}

//判断是否需要记录该文件
func (f *FileLogger) enable(logLevel LogLevel) bool {
	return logLevel >= f.Level
}

//判断文件是否需要切割
func (f *FileLogger) checkSize(file *os.File) bool {
	fileInfo, err := f.fileObj.Stat()
	if err != nil {
		fmt.Printf("open file failed,err:\n", err)
	}
	//如果当前文件大于等于 日志文件的最大值，就应该返回true
	return fileInfo.Size() >= f.maxFileSize
}

//切割文件
func (f *FileLogger) splite(file *os.File) (*os.File, error) {
	//需要切割日志文件
	nowStr := time.Now().Format("20060102150405000")
	fileInfo, err := file.Stat()
	if err != nil {
		fmt.Printf("open file failed,err:\n", err)
		return nil, err
	}
	logName := path.Join(f.filePath, fileInfo.Name()) //拿到当前日志文件完整路径
	//1.关闭当前的日志文件
	file.Close()
	//2.备份一下 rename xx.log---> xx.log.bak202201091122
	newlogName := fmt.Sprintf("%s.bak%s", logName, nowStr) //拼接一个日志文件备份名称
	os.Rename(logName, newlogName)
	//3.打开一个新的日志文件
	fileObj, err1 := os.OpenFile(logName, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
	if err1 != nil {
		fmt.Printf("open log file failed,err1:%v\n", err1)
		return nil, err
	}
	//4.将打开的新日志文件对象赋值给f.fileObj
	return fileObj, nil
}

func (f *FileLogger) log(lv LogLevel, format string, a ...interface{}) {
	if f.enable(lv) {
		msg := fmt.Sprintf(format, a...)
		now := time.Now()
		funcName, fileName, lineNO := getInfo(3)
		if f.checkSize(f.fileObj) {
			newFile, err := f.splite(f.fileObj)
			if err != nil {
				fmt.Printf("open log file failed,err:%v\n", err)
				return
			}
			f.fileObj = newFile
		}
		fmt.Fprintf(f.fileObj, "[%s] [%v] [%s:%s:%d] %s \n", now.Format("2006-01-02 15:04:05"), getLogstring(lv), funcName, fileName, lineNO, msg)
		//如果要记录的日志大于等于ERROR级别，我还要在err日志文件中再记录一次
		if lv >= ERROR {
			if f.checkSize(f.errFileObj) {
				newFile, err1 := f.splite(f.errFileObj)
				if err1 != nil {
					fmt.Printf("open log file failed,err1:%v\n", err1)
					return
				}
				f.errFileObj = newFile
			}
			fmt.Fprintf(f.errFileObj, "[%s] [%v] [%s:%s:%d] %s \n", now.Format("2006-01-02 15:04:05"), getLogstring(lv), funcName, fileName, lineNO, msg)
		}
	}
}

func (f *FileLogger) Debug(format string, a ...interface{}) {
	f.log(DEBUG, format, a...)
}
func (f *FileLogger) Info(format string, a ...interface{}) {
	f.log(INFO, format, a...)
}
func (f *FileLogger) Warning(format string, a ...interface{}) {
	f.log(WARNING, format, a...)
}
func (f *FileLogger) Error(format string, a ...interface{}) {
	f.log(ERROR, format, a...)
}
func (f *FileLogger) Fatal(format string, a ...interface{}) {
	f.log(FATAL, format, a...)
}
